/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds;

import java.awt.event.KeyEvent;
import java.util.ArrayList;
import net.worlds.input.InputState;
import net.worlds.object.AngularVelocityController;
import net.worlds.object.AssetService;
import net.worlds.object.Camera;
import net.worlds.object.Part;
import net.worlds.object.Character;
import net.worlds.object.Ladder;
import net.worlds.object.Player;
import net.worlds.object.Tool;
import net.worlds.object.VelocityController;
import net.worlds.ui.UI;
import org.jbox2d.common.Vec2D;


public class LocalPlayer {
    private Character character = null;
    private VelocityController controller = null;
    private AngularVelocityController rcontroller = null;
    private Ladder ladder;
    private Part torso;
    private Player player;
    public boolean isJumping;
    private ArrayList<Tool> tools = new ArrayList<Tool>(16);
    private Tool selectedTool;
    public boolean enableArmRotation = false;
    private float speed;
    public int d = 0;
    public int rd = 0;
    private boolean isRunning;
    private long lastJumpTime;
    private int toolIndex = -1;
    public LocalPlayer(Player p) throws WorldsException
    {
        if(p == null)
            throw new RuntimeException("player == nil!");
        player = p;
        if(p.getObjectProp("Character") == null || !(p.getObjectProp("Character") instanceof Character))
            return;
        character = (Character) p.getObjectProp("Character");
        if(character.hasChild("Body") && character.getChild("Body") instanceof Part)
        {
            torso = (Part) character.getChild("Body");
            torso.isCharacter = true;
            torso.isRemoteCharacter = false;
        }
        if(torso.hasChild("Controller") && torso.getChild("Controller") instanceof VelocityController)
            controller = (VelocityController) torso.getChild("Controller");
        if(torso.hasChild("RotationController") && torso.getChild("RotationController") instanceof AngularVelocityController)
            rcontroller = (AngularVelocityController) torso.getChild("RotationController");
        if(p.hasChild("Camera") && p.getChild("Camera") instanceof Camera)
        {
            Main.getGame().currentCamera = (Camera) p.getChild("Camera");
            Main.getGame().currentCamera.setProp("ScaleFactor", 8.0f, true);
            Main.getGame().currentCamera.setProp("FollowObject", torso, true);
        }
        speed = (float) player.getFloatProp("Speed");
    }
    public Player getPlayer()
    {
        return player;
    }
    public Character getCharacter()
    {
        return character;
    }
    public Part getTorso()
    {
        return torso;
    }
    public void clearTools()
    {
        selectedTool = null;
        tools.clear();
    }
    public void addTool(Tool t)
    {
        Util.checkThread();
        tools.add(t);
    }
    public void removeTool(Tool t)
    {
        Util.checkThread();
        tools.remove(t);
    }
    public Tool getSelectedTool()
    {
        if(character == null || character.isDead)
            return null;
        return selectedTool;
    }
    public int getSelectedToolIndex()
    {
        return toolIndex;
    }
    public void deselectTool()
    {
        if(selectedTool != null)
            selectedTool.deselected();
        selectedTool = null;
    }
    public void setSelectedTool(int idx) throws WorldsException
    {
        if(character == null || character.isDead)
            return;
        Util.checkThread();
        enableArmRotation = false;
        if(idx < tools.size() && idx >= 0)
        {
            if(selectedTool == tools.get(idx))
            {
                selectedTool.deselected();
                selectedTool = null;
                toolIndex = -1;
            }
            else
            {
                UI.oldMouseMode = UI.mouseMode;
                if(selectedTool != null)
                    selectedTool.deselected();
                selectedTool = tools.get(idx);
                selectedTool.selected();
                if(selectedTool.getBooleanProp("Holdable"))
                    enableArmRotation = true;
                toolIndex = idx;
            }
            if(Main.isClient())
                Main.getClient().sendSelectedTool(selectedTool);
            ((AssetService)Main.getGame().getMainWorld().getService("AssetService")).playSound("Click");
        }
    }
    public ArrayList<Tool> getTools()
    {
        return (ArrayList<Tool>) tools.clone();
    }
    public void setLadder(Ladder l)
    {
        if(ladder == l || (l != null && l.disabled))
            return;
        try {
            ladder = l;
            if(l == null)
            {
                controller.setProp("Velocity", new Vec2D(controller.getVec2DProp("Velocity").x, 0), true);
            }
            else
            {
                if(InputState.pressedKeyCodes.contains(KeyEvent.VK_UP) || InputState.pressedKeyCodes.contains(KeyEvent.VK_W))
                {
                    Vec2D v = new Vec2D(ladder.getBody().getAngle() + Math.PI/2).mul(5).add(controller.getVec2DProp("Velocity"));
                    controller.setProp("Velocity", v, true);
                }
            }
        } catch (WorldsException ex) {
            ex.printStackTrace();
        }
    }
    public void processKeyDown(int k)
    {
        if(character == null || character.isDead)
            return;
        try {
            float s = (float) speed;
            if(isRunning)
                s *= (3/2f);
            if (controller == null || !controller.isInWorld())
                return;
            Vec2D oldV = controller.getVec2DProp("Velocity");
            if(k == KeyEvent.VK_SHIFT && !isRunning)
            {
                isRunning = true;
                if(d == 1)
                    controller.setProp("Velocity", new Vec2D(s * (3/2f), oldV.y), true);
                else if(d == -1)
                    controller.setProp("Velocity", new Vec2D(-s * (3/2f), oldV.y), true);
            }
            if (character.seat == null && (k == KeyEvent.VK_LEFT || k == KeyEvent.VK_A)) {
                if(Main.getGame().type == 0)
                {
                    torso.noFriction = true;
                    controller.setProp("Velocity", new Vec2D(-s, oldV.y), true);
                    d = -1;
                }
                else
                {
                    rcontroller.setProp("Velocity", 5.0f, true);
                    rd = 1;
                }
            } else if (character.seat == null && (k == KeyEvent.VK_RIGHT || k == KeyEvent.VK_D)) {
                if(Main.getGame().type == 0)
                {
                    torso.noFriction = true;
                    controller.setProp("Velocity", new Vec2D(s, oldV.y), true);
                    d = 1;
                }
                else
                {
                    rcontroller.setProp("Velocity", -5.0f, true);
                    rd = -1;
                }
            }
            else if(k == KeyEvent.VK_UP || k == KeyEvent.VK_W)
            {
                if(character.seat != null)
                {
                    character.setSeat(null);
                }
                if(ladder != null)
                {
                    Vec2D v = new Vec2D(ladder.getBody().getAngle() + Math.PI/2).mul(5);
                    controller.setProp("Velocity", v, true);
                }
                else
                {
                    if(!torso.hasChild("Controller"))
                        return;
                    else if((torso.inWater && System.currentTimeMillis() - lastJumpTime < 900) || (!torso.inWater && isJumping))
                        return;
                    if(Main.getGame().type == 0)
                    {
                        torso.setProp("Velocity", new Vec2D(torso.getVelocity().x, (float) player.getFloatProp("JumpForce")), true);
                        isJumping = true;
                        lastJumpTime = System.currentTimeMillis();
                        torso.inWater = false;
                    }
                    else
                    {
                        torso.noFriction = true;
                        controller.setProp("Velocity", new Vec2D(oldV.x, s), true);
                        d = 2;
                    }
                }
            }
            else if(k == KeyEvent.VK_DOWN || k == KeyEvent.VK_S)
            {
                if(Main.getGame().type == 0 && torso != null && torso.inWater)
                {
                    controller.setProp("Velocity", new Vec2D(oldV.x, -5), true);
                    torso.inWater = false;
                }
                else if(Main.getGame().type > 0)
                {
                    torso.noFriction = true;
                    controller.setProp("Velocity", new Vec2D(oldV.x, -s), true);
                    d = -2;
                }
            }
            else if(k == KeyEvent.VK_Q)
            {
                Tool t = selectedTool;
                if(t != null && t.getBooleanProp("Holdable"))
                {
                    selectedTool = null;
                    enableArmRotation = false;
                    t.deselected();
                    t.drop();
                    Vec2D vec = new Vec2D(-character.mouseAngle).mul(t.getVec2DProp("Size").x/2 + 2.5f + t.getVec2DProp("TextureOffset").x);
                    t.setProp("Rotation", (float) Math.toDegrees(-character.mouseAngle), true);
                    t.setProp("Position", torso.getPosition().add(vec), true);
                }
            }
        } catch (WorldsException ex) {
            throw new RuntimeException(ex);
        }
    }
    public void processKeyUp(int k)
    {
        if(character == null || character.isDead)
            return;
        try
        {
            if (controller == null || !controller.isInWorld())
                return;
            float oldY = controller.getVec2DProp("Velocity").y;
            float oldX = controller.getVec2DProp("Velocity").x;
            if(k == KeyEvent.VK_SHIFT && isRunning)
            {
                isRunning = false;
                if(d == 1)
                    controller.setProp("Velocity", new Vec2D(speed * (2/3f), oldY), true);
                else if(d == -1)
                    controller.setProp("Velocity", new Vec2D(speed * (-2/3f), oldY), true);
            }
            if ((k == KeyEvent.VK_LEFT || k == KeyEvent.VK_A) && controller.getVec2DProp("Velocity").x < 0)
            {
                d = 0;
                torso.noFriction = false;
                controller.setProp("Velocity", new Vec2D(0, oldY), true);
            }
            else if((k == KeyEvent.VK_RIGHT || k == KeyEvent.VK_D) && controller.getVec2DProp("Velocity").x > 0)
            {
                d = 0;
                torso.noFriction = false;
                controller.setProp("Velocity", new Vec2D(0, oldY), true);
            }
            else if(Main.getGame().type != 0 && (k == KeyEvent.VK_RIGHT || k == KeyEvent.VK_D) && rcontroller.getFloatProp("Velocity") < 0)
            {
                rd = 0;
                rcontroller.setProp("Velocity", 0.0f, true);
            }
            else if(Main.getGame().type != 0 && (k == KeyEvent.VK_LEFT || k == KeyEvent.VK_A) && rcontroller.getFloatProp("Velocity") > 0)
            {
                rd = 0;
                rcontroller.setProp("Velocity", 0.0f, true);
            }
            else if(Main.getGame().type != 0 && (k == KeyEvent.VK_UP || k == KeyEvent.VK_W) && controller.getVec2DProp("Velocity").y > 0)
            {
                d = 0;
                torso.noFriction = false;
                controller.setProp("Velocity", new Vec2D(oldX, 0), true);
            }
            else if(Main.getGame().type != 0 && (k == KeyEvent.VK_DOWN || k == KeyEvent.VK_S) && controller.getVec2DProp("Velocity").y < 0)
            {
                d = 0;
                torso.noFriction = false;
                controller.setProp("Velocity", new Vec2D(oldX, 0), true);
            }
            else if(Main.getGame().type == 0 && (k == KeyEvent.VK_W || k == KeyEvent.VK_UP))
            {
                if(ladder != null)
                {
                    controller.setProp("Velocity", new Vec2D(controller.getVec2DProp("Velocity").x, 0), true);
                }
            }
            else if(Main.getGame().type == 0 && (k == KeyEvent.VK_DOWN || k == KeyEvent.VK_S))
            {
                if(controller.getVec2DProp("Velocity").y == -5)
                    controller.setProp("Velocity", new Vec2D(controller.getVec2DProp("Velocity").x, 0), true);
            }
        }
        catch(WorldsException ex)
        {
            throw new RuntimeException(ex);
        }
    }
    public void setSpeed(float v)
    {
        speed = v;
        if(Main.getGame().type == 0)
        {
            if(this.d == 1)
            {
                if(isRunning)
                    try {
                        controller.setProp("Velocity", new Vec2D(speed, controller.getVec2DProp("Velocity").y), true);
                    } catch (WorldsException ex) {
                    }
                else
                    try {
                        controller.setProp("Velocity", new Vec2D((3/2f) * speed, controller.getVec2DProp("Velocity").y), true);
                    } catch (WorldsException ex) {
                    }
            }
            else if(d == -1)
            {
                if(isRunning)
                    try {
                        controller.setProp("Velocity", new Vec2D(-speed, controller.getVec2DProp("Velocity").y), true);
                    } catch (WorldsException ex) {
                    }
                else
                    try {
                        controller.setProp("Velocity", new Vec2D((3/2f) * -speed, controller.getVec2DProp("Velocity").y), true);
                    } catch (WorldsException ex) {
                    }
            }
        }
        else
        {
            if(d == 2)
            {
                try {
                    controller.setProp("Velocity", new Vec2D(controller.getVec2DProp("Velocity").x, speed), true);
                } catch (WorldsException ex) {
                }
            }
        }
    }
}
